﻿// <copyright file="NotificationHelper.cs" company="http://www.dymetis.com">
//
// Copyright (c) 2011 Eddie Z. Lin.
//
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.
// All other rights reserved.
// 
// </copyright>

namespace Dymetis.TeamAlert
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Net.Mail;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    using System.Xml.XPath;
    using System.Xml.Xsl;
    using Dymetis.TeamAlert.Configuration;
    using Microsoft.TeamFoundation.Framework.Server;

    internal sealed class NotificationHelper
    {
        private readonly string fromAddress;
        private readonly string smtpServer;
        private readonly bool emailEnabled;
        private readonly string xslSearchPath;

        private const string PlainTextXslExtension = "plainTextXsl";
        private const string XslExtension = "xsl";

        private const string DefaultXslPath = "../TFSJobAgent/Transforms";
        private const string RegistryPath = "/Service/Integration/Settings/*";

        private const int MaxSubjectLength = 150;

        public NotificationHelper(TeamFoundationRequestContext requestContext, AlertSettingsConfigurationElement alertSettings)
        {
            var registryService = requestContext.GetService<TeamFoundationRegistryService>();
            var entrys = registryService.ReadEntriesFallThru(requestContext, RegistryPath);

            this.fromAddress = String.IsNullOrWhiteSpace(alertSettings.FromAddress) ? entrys["EmailNotificationFromAddress"].GetValue(string.Empty) : alertSettings.FromAddress;
            this.smtpServer = String.IsNullOrWhiteSpace(alertSettings.SmtpServer) ? entrys["SmtpServer"].GetValue(string.Empty) : alertSettings.SmtpServer;

            this.emailEnabled = alertSettings.EmailEnabled;

            this.xslSearchPath = String.IsNullOrWhiteSpace(alertSettings.XslSearchPath) ? DefaultXslPath : alertSettings.XslSearchPath;
            if (!Path.IsPathRooted(this.xslSearchPath))
            {
                this.xslSearchPath = Path.Combine(requestContext.ServiceHost.PhysicalDirectory, this.xslSearchPath);
            }

            this.xslSearchPath = new FileInfo(this.xslSearchPath).FullName;
        }

        public void SendMailNotification(TeamFoundationRequestContext requestContext, XDocument eventDocument, AlertRecipient recipient, bool isHtml, bool attachRawEvent)
        {
            if (!this.emailEnabled)
            {
                return;
            }

            var eventType = eventDocument.Root.Name.LocalName;
            
            string subject = GetMailSubject(eventDocument, eventType);

            var message = new MailMessage();
            message.Body = this.Format(eventType, eventDocument, isHtml);
            message.BodyEncoding = Encoding.UTF8;
            message.IsBodyHtml = isHtml;
            message.Subject = subject;
            message.SubjectEncoding = Encoding.UTF8;
            message.From = new MailAddress(this.fromAddress);

            message.To.Add(new MailAddress(recipient.EmailAddress, recipient.DisplayName));

            using (SmtpClient client = new SmtpClient(this.smtpServer))
            {
                client.UseDefaultCredentials = true;

                if (attachRawEvent)
                {
                    using (var stream = new MemoryStream())
                    {
                        eventDocument.Save(stream);

                        stream.Seek(0, SeekOrigin.Begin);

                        var eventAttchment = new Attachment(stream, eventType + ".xml");

                        message.Attachments.Add(eventAttchment);
                        client.Send(message);
                    }
                }
                else
                {
                    client.Send(message);
                }
            }
        }

        private static string GetMailSubject(XDocument eventDocument, string eventType)
        {
            var navigator = eventDocument.CreateNavigator();
            string xpath = String.Format(CultureInfo.InvariantCulture, "{0}/Title", new object[] { eventType });
            var iterator = navigator.Evaluate(xpath) as XPathNodeIterator;

            string subject = eventType;
            if ((iterator != null) && iterator.MoveNext())
            {
                subject = iterator.Current.Value;
            }

            if (subject.Length > MaxSubjectLength)
            {
                subject = subject.Substring(0, MaxSubjectLength - 3) + "...";
            }

            return subject;
        }

        private string Format(string eventType, XDocument eventDocument, bool isHtml)
        {
            string xslExtension = isHtml ? XslExtension : PlainTextXslExtension;

            string path = Path.Combine(this.xslSearchPath, eventType + "." + xslExtension);

            XslCompiledTransform transform = new XslCompiledTransform();
            transform.Load(path);
            using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                using (XmlTextWriter xmlWriter = new XmlTextWriter(writer))
                {
                    using (var reader = eventDocument.CreateReader())
                    {
                        transform.Transform(reader, null, xmlWriter);
                        return writer.ToString();
                    }
                }
            }
        }
    }
}
